package com.zzyl.nursing.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.dto.DeviceDataPageReqDto;
import com.zzyl.nursing.dto.IotMsgNotifyData;
import com.zzyl.nursing.dto.IotMsgService;
import com.zzyl.nursing.mapper.DeviceDataMapper;
import com.zzyl.nursing.service.IDeviceDataService;
import com.zzyl.nursing.service.IDeviceService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 设备数据功能Service业务层处理
 *
 * @author mr.chen
 * @date 2025-05-25
 */
@Service
public class DeviceDataServiceImpl extends ServiceImpl<DeviceDataMapper, DeviceData> implements IDeviceDataService {
    @Autowired
    private DeviceDataMapper deviceDataMapper;

    /**
     * 查询设备数据功能
     *
     * @param id 设备数据功能主键
     * @return 设备数据功能
     */
    @Override
    public DeviceData selectDeviceDataById(Long id) {
        return getById(id);
    }

    /**
     * 查询设备数据功能列表
     *
     * @param dto 设备数据功能
     * @return 设备数据功能
     */
    @Override
    public Page<DeviceData> selectDeviceDataList(DeviceDataPageReqDto dto) {
        Page<DeviceData> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        this.lambdaQuery()
                .orderByDesc(DeviceData::getAlarmTime)
                .eq(StringUtils.isNotEmpty(dto.getDeviceId()), DeviceData::getIotId, dto.getDeviceId())
                .eq(StringUtils.isNotEmpty(dto.getDeviceName()), DeviceData::getDeviceName, dto.getDeviceName())
                .eq(StringUtils.isNotEmpty(dto.getFunctionId()), DeviceData::getFunctionId, dto.getFunctionId())
                .between(dto.getStartTime() != null && dto.getEndTime()!=null, DeviceData::getAlarmTime, dto.getStartTime(), dto.getEndTime())
                .page(page);
      return page;
    }

    /**
     * 新增设备数据功能
     *
     * @param deviceData 设备数据功能
     * @return 结果
     */
    @Override
    public int insertDeviceData(DeviceData deviceData) {
        return save(deviceData) ? 1 : 0;
    }

    /**
     * 修改设备数据功能
     *
     * @param deviceData 设备数据功能
     * @return 结果
     */
    @Override
    public int updateDeviceData(DeviceData deviceData) {
        return updateById(deviceData) ? 1 : 0;
    }

    /**
     * 批量删除设备数据功能
     *
     * @param ids 需要删除的设备数据功能主键
     * @return 结果
     */
    @Override
    public int deleteDeviceDataByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除设备数据功能信息
     *
     * @param id 设备数据功能主键
     * @return 结果
     */
    @Override
    public int deleteDeviceDataById(Long id) {
        return removeById(id) ? 1 : 0;
    }

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 将获取到的设备上报数据进行解析，批量保存到设备数据表中
     *
     * @param contentStr
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleMessage(String contentStr) {
        //判断数据是否合法
        if (StringUtils.isBlank(contentStr)) {
            throw new BaseException("数据非法");
        }
        //转成对象
        JSONObject massage = JSONUtil.parseObj(contentStr);
        //获取notify_data属性内容
        Object notifyDataJSON = massage.getObj("notify_data");
        if (notifyDataJSON == null) {
            throw new BaseException("数据非法");
        }
        //转成对象
        JSONObject notifyData = JSONUtil.parseObj(notifyDataJSON);
        //获取header内容
        Object header = notifyData.getObj("header");
        //获取body内容
        Object body = notifyData.getObj("body");
        if (header == null || body == null) {
            throw new BaseException("数据非法");
        }
        //转成实体对象
        IotMsgNotifyData iotMsgNotifyData = JSONUtil.toBean(notifyData, IotMsgNotifyData.class);
        //获取设备id
        String iotId = iotMsgNotifyData.getHeader().getDeviceId();
        //查看该设备是否存在
        Device device = deviceService.lambdaQuery()
                .eq(Device::getIotId, iotId)
                .one();
        if (device == null) {
            throw new BaseException("该设备不存在");
        }
        //设备数据封装
        List<IotMsgService> services = iotMsgNotifyData.getBody().getServices();
        ArrayList<DeviceData> deviceDataList = new ArrayList<>();
        services.forEach(s -> {
            //获取上报时间
            String eventTime = s.getEventTime();
            LocalDateTime alarmTime = OffsetDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX"))
                    .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            Map<String, Object> properties = s.getProperties();
            properties.forEach((k, v) -> {
                DeviceData deviceData = new DeviceData();
                BeanUtils.copyProperties(device, deviceData, "id");
                deviceData.setDataValue(String.valueOf(v));//物模型属性值
                deviceData.setFunctionId(k);//功能名（设备物模型属性名）
                deviceData.setAlarmTime(alarmTime);//上报时间
                deviceData.setAccessLocation(device.getBindingLocation());//绑定位置（接入位置）
                deviceDataList.add(deviceData);
            });
        });
        //保存数据
        boolean saveBatch = this.saveBatch(deviceDataList);
        if (!saveBatch) {
            throw new BaseException("保存数据失败");
        }
        //存储到redis
        redisTemplate.opsForHash().put(CacheConstants.HUAWEU_IOTDA_DEVICE_DATA_LIST,iotId, JSONUtil.toJsonStr(deviceDataList));
    }
}

